import json5
from pathlib import Path
import sys
from sqlalchemy import create_engine, String, Integer, Boolean, DateTime
from sqlalchemy.pool import QueuePool
from YKSqlalchemy import SqlOperator, YkColumn
from flaskserver import start_server_app
import logging
import traceback
import datetime

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def login(args):
    """
    查询登录用户信息是否正确，返回注册结果
    """
    import datetime
    username = args['username']
    encrypt_pass = args['password']
    app = args.get('app')
    sql: SqlOperator = args['sql']
    try:
        res = sql.select_in_table(table_name='user', condition_dict={'username': username, 'password': encrypt_pass},
                                  result_type='json')

        if res:  # 成功登录后，余额减1
            today = datetime.date.today()
            last_login_time: datetime.datetime = res.get("last_login")
            if last_login_time is None:
                last_login_time = datetime.datetime.now()

            last_login_date = last_login_time.date()
            if last_login_date != today:  # 如果最后登录日期不是今天，则余额减1
                money = res.get("money") - 1
                if money < -20:
                    return {
                        "success": True,
                        "login_res_type": 2,  # 2表示积分不足，需要充值，1元=10积分
                        "login_info": res,
                    }
            else:
                money = res.get("money")

            sql.update_item(table_name='user', conditions={'username': username, 'password': encrypt_pass},
                            values={"money": money, "last_login": datetime.datetime.now()})
            return {
                "success": True,
                "login_res_type": 0,  # 0表示成功登录，否则失败
                "login_info": res,
            }
        else:
            return {
                "success": True,
                "login_res_type": 1,  # 用户不存在或密码错误
                "login_info": res
            }

    except Exception as e:
        logger.debug(e)
        traceback.print_exc()
        return {
            "success": False,
            "login_res_type": 3,  # 3表示服务器内部错误，可能是数据库错误
            "login_info": str(e)
        }


def register(args):
    """
    注册用户，向mysql数据库表中添加用户
    """
    import datetime
    sql: SqlOperator = args['sql']
    username = args['username']
    encrypt_pass = args['password']
    email = args['email']
    money = 0
    vip = 0
    last_login = datetime.datetime.now()

    if sql.exists_in_table('user', condition_dict={'username': username}):
        return {
            "success": True,
            "register_res_type": 1,
            "register_info": "duplicated username"
        }
    elif sql.exists_in_table("user", condition_dict={'email': email}):
        return {
            "success": True,
            "register_res_type": 2,
            "register_info": "duplicated email"
        }
    else:
        sql.insert_item('user', values=[username, email, encrypt_pass, money, vip, last_login],
                        col_names=['username', 'email', 'password', "money", "vip", "last_login"])
        return {"success": True,
                "register_res_type": 0,
                "register_info": "success", }


def charge(args):
    """
    向指定账号充值
    """
    logger.debug(args)
    name = args.get('name')  # 充值的title, `${username}-${app}-${money}元`
    username, app, _money = name.split('-')
    money = args.get('money')  # 单位元
    money = int(float(money)) * 10  # 将单位转换成角
    pid = args.get('pid')  # 充值接口的识别码
    no = args.get('out_trade_no')  # 订单号,自己生成。我是当前时间YYYYMMDDHHmmss再加上随机三位数
    site_name = args.get('sitename')  # 充值的网站名称
    trade_status = args.get('trade_status')  # 充值状态
    sql: SqlOperator = args.get('sql')
    logger.debug(f"{username}, {pid}, {no}, {site_name}, {trade_status}")

    # https://z-pay.cn/submit.php?money=1&name=undefined-SGES-1%E5%85%83out_trade_no=1733882848665&pid=2024120914335319
    try:
        exist_no = sql.select_item('trade', {"no": no})
        logger.debug(f"{exist_no=}, {trade_status=}")
        if trade_status == "TRADE_SUCCESS" and not exist_no:
            now_money = int(sql.select_item(
                'user', {"username": username}, result_col='money'))
            logger.debug(f"{now_money=}")
            conditions = {"username": username}
            values = {"money": now_money + money}
            logger.debug(f"{conditions=}, {values=}")
            sql.update_item('user', conditions, values)
            sql.insert_item('trade', values=[no, username, money, app, pid, trade_status],
                            col_names=['no', 'username', 'amount', 'app', 'pid', 'status'])
            logger.debug(f"充值成功")
            return "success"
        else:
            return "success"  # 告诉支付官方通知收到，不要再次发送了
    except Exception as e:
        logger.debug(traceback.format_exc())
        logger.debug(e)
        return "error"  # 告诉官方再次尝试发送充值信息


def testrest(args):
    return {
        "success": True,
        "info": '服务正在运行中...',
        "args": str(args)
    }


def GetPoolInfo(args):
    sql: SqlOperator = args['sql']
    return {
        "success": True,
        "info": sql.get_pool_info()
    }


def systemTick(args):
    sql: SqlOperator = args.get('sql')
    username = args.get('username')
    try:
        last_login, money = sql.select_item(
            'user', {"username": username}, result_col=['last_login', 'money'])
        if last_login.date() == datetime.date.today():
            now_money = int(money)  # 当天已经登录，则不进行操作
        else:
            # 当前未登录，则扣费后将最后登录时间更改为今天
            now_money = int(money) - 1
            sql.update_item('user', {"username": username},
                            values={'money': now_money, 'last_login': datetime.datetime.now()})
        if now_money < -10:
            return {
                "username": username,
                "isLogin": True,
                "money": now_money,
                "status": "arrear"
            }
        else:
            return {
                "username": username,
                "isLogin": True,
                "money": now_money,
                "status": "success"
            }
    except Exception as e:
        traceback.print_exc()
        logger.debug(e)
        return {
            "username": username,
            "isLogin": False,
            "status": "Server Error"
        }


def load_config():
    """Load configuration from settings.json file."""
    config_path = Path("config/settings.json")
    if not config_path.exists():
        # 尝试从 ./config 子目录查找
        config_path = Path("config") / "settings.json"
        if not config_path.exists():
            logger.error("Configuration file not found in current directory or config subdirectory.")
            sys.exit(1)

    try:
        with open(config_path, "r", encoding="utf-8") as f:
            return json5.load(f)
    except Exception as e:
        logger.error(f"Error loading configuration: {e}")
        sys.exit(1)


def start_restful_mysql(mysql_user, mysql_password, mysql_host='localhost', mysql_port=3306, mysql_db='sges',
                        rest_port=5000, cors=True, single_thread=False):
    sql = SqlOperator(
        create_engine(f'mysql+pymysql://{mysql_user}:{mysql_password}@{mysql_host}:{mysql_port}/{mysql_db}',
                      poolclass=QueuePool,
                      pool_size=5,
                      max_overflow=10,
                      pool_timeout=30,  # 连接池中没有可用连接时的等待时间，超过该时间还没有可用连接，则报错
                      pool_recycle=3600,  # 连接池中的连接1小时后会回收
                      pool_pre_ping=True,  # 每次连接请求时，先测试返回的连接是否还存活，不存活则从连接池中取下一个连接
                      ))

    # 检查mysql服务器login_reg数据库中是否存在user表，不存在则创建
    if not sql.exist_table('user'):
        sql.create_table('user', [
            YkColumn('username', String(20), primary_key=True),
            YkColumn('email', String(50)),
            YkColumn('password', String(100)),  # 加密后的密码长度为96位
            YkColumn('money', Integer),
            YkColumn('vip', Boolean),
            YkColumn('last_login', DateTime),
        ])
    # 检查mysql服务器login_reg数据库中是否存在trade表，不存在则创建
    if not sql.exist_table('trade'):
        sql.create_table('trade', [  # 'no', 'username', 'amount', 'name', 'pid', 'status'
            YkColumn('no', String(20), primary_key=True),
            YkColumn('username', String(20)),
            YkColumn('amount', Integer),
            YkColumn('app', String(50)),
            YkColumn('pid', String(20)),
            YkColumn('status', String(20)),
            YkColumn('date', DateTime)
        ])

    def deal(args):
        try:
            # 因为下方use_action=True，所以这里的action必然有值，避免eval函数出错
            action = args.get('action')
            args['sql'] = sql

            result = eval(f"{action}(args)")
            return result
        except Exception as e:
            logger.error(f"执行deal时错误: {e}")
            logger.error(traceback.format_exc())
            return {"success": False,
                    "info": f"执行deal时错误: {e}"}

    start_server_app(deal=deal, use_action=True,
                     allow_action=['login', 'register', 'charge', 'testrest', 'GetPoolInfo',
                                   'systemTick'],
                     host='0.0.0.0',
                     port=rest_port,
                     example_url=[
                         f'http://localhost:{rest_port}/?Action=login&username=杨可&password=test'],
                     single_thread=single_thread, cors=cors)


def main():
    """Main function to start the service."""
    config = load_config()
    db_config = config["database"]
    server_config = config["server"]

    mysql_user = db_config.get('user', 'root')
    mysql_password = db_config.get('password', '')
    mysql_host = db_config.get('host', 'localhost')
    mysql_port = db_config.get('port', 3306)
    mysql_db = db_config.get('database', 'login_reg')

    rest_port = 5000
    cors = server_config.get('cors', True)
    single_thread = False

    start_restful_mysql(mysql_user, mysql_password, mysql_host, mysql_port, mysql_db,
                        rest_port, cors, single_thread)


if __name__ == '__main__':
    # 本程序运行需要在main.py下添加配置文件settings.toml，内容格式如下：
    """
[database]
host = "localhost"
port = 3306
user = "root"
password = "password"
database = "login_reg"

[server]
cors = true
"""
    main()
